package thread;

public class SyncDemo2 {
    public static void main(String[] args){
        Shop shop = new Shop();
        Thread yjp = new Thread("yjp"){
            @Override
            public void run(){
                shop.buy();
            }
        };
        Thread yyy = new Thread("yyy"){
            @Override
            public void run(){
                shop.buy();
            }
        };
     yjp.start();
        yyy.start();
    }
}
/*
            同步块可以更精准的控制需要同步执行的代码片段
            但是使用同步块时要指定同步监视器对象,同步监视器对象要同时具备以下条件:
            1:必须是引用类型实例
            2:多个需要同步执行该代码片段的线程看到的必须是同一个对象

            合适的锁对象,应当是在多个线程出现"抢"的时候发挥左右,否则不发发挥作用
            例如:两个线程分别执行两个Shop实例的buy方法(相当于两个人去不同的商店)时,那么这两个
            线程就不发生"抢"的现象,此时下面的同步块就不应当要求线程排队执行代码.
            如果同步监视器对象选取了字符串字面量(字符串字面量在任何情况下都是同一个对象),那么在
            这样的情况下也要求多个线程排队执行显然是不合适的.
         */
            /*
                synchronized不是公平锁,当一个线程进入后,如果后续有5个线程陆续执行到这里开始排队时
                当进入的线程出了同步块后,并不是后五个中先排队的线程先进入,而是后五个线程谁先拿到时间片
                谁先进入执行.
                如果想实现公平锁,可以使用JUC(java.util.concurrent包),java并发包
                这个包中包含了很多和并发相关的API.

                java.util.concurrent.locks.ReentrantLock 可重入锁可以实现公平锁机制
             */
class Shop{
    public   void buy(){
        try {
            Thread t = Thread.currentThread();
            System.out.println(t.getName()+"挑选衣服");
            Thread.sleep(5000);
            synchronized (this) {
//                synchronized (new Object()){
                System.out.println(t.getName()+"试穿衣服");
                Thread.sleep(5000);
            }
            System.out.println(t.getName()+"结账");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}